﻿using System.Collections.Generic;

namespace RedNoteModule
{
    /// <summary>
    /// 红点结构树
    /// </summary>
    public class RedNoteRelationTree
    {
        private Dictionary<string, RedNote> m_allRedNotes = new Dictionary<string, RedNote>();

        private Dictionary<string, bool> m_dirtyRedNotes = new Dictionary<string, bool>();
        
        #region 节点关系部分

        public void AddRelation(string parent, string child)
        {
            if (!m_allRedNotes.ContainsKey(parent))
            {
                CreateNote(parent);
            }
            if (!m_allRedNotes.ContainsKey(child))
            {
                CreateNote(child);
            }
            
            m_allRedNotes[child].ClearParent();
            m_allRedNotes[child].SetParent(m_allRedNotes[parent]);
            m_allRedNotes[parent].AddChild(m_allRedNotes[child]);
        }

        public void AddRelations(string parent, string[] children)
        {
            for (int i = 0; i < children.Length; i++)
            {
                AddRelation(parent, children[i]);
            }
        }
        
        public void RemoveRelation(string parent, string child)
        {
            if (!m_allRedNotes.ContainsKey(parent) || !m_allRedNotes.ContainsKey(child))
            {
                return;
            }
            
            var childNote =m_allRedNotes[child]; 
            var parentNote = m_allRedNotes[parent];
            var chg = parentNote.AfterChildStateUpdate(child, false);
            if (chg)
            {
                MarkDirty(parentNote.Key, parentNote.State);
            }
            
            childNote.ClearParent();
            parentNote.RemoveChild(child);
        }

        public bool ContainsNote(string key)
        {
            return m_allRedNotes.ContainsKey(key);
        }

        public RedNote CreateNote(string key)
        {
            if (!m_allRedNotes.TryGetValue(key, out RedNote note))
            {
                note = new RedNote(key);
                m_allRedNotes.Add(key, note);
            }
            return note;
        }
        
        public RedNote GetNote(string key)
        {
            if (m_allRedNotes.TryGetValue(key, out RedNote note))
            {
                return note;
            }
            return null;
        }

        public bool GetNoteState(string key)
        {
            if (m_allRedNotes.TryGetValue(key, out RedNote note))
            {
                return note.State;
            }
            return false;
        }

        public void DestroyNote(string key, bool recursive = false)
        {
            if (m_allRedNotes.TryGetValue(key, out RedNote note))
            {
                //子节点销毁
                if (note.ChildrenCount <= 0)
                {
                    if (!note.IsRoot)
                    {
                        RemoveRelation(note.Parent.Key, note.Key);
                    }

                    if (note.State)
                    {
                        //销毁自身的时候把关联到自己的红点熄灭
                        MarkDirty(note.Key, false);
                    }
                    m_allRedNotes.Remove(key);
                    note.Destroy();

                    return;
                }
                
                //递归销毁
                if (recursive && note.ChildrenCount > 0)
                {
                    var waitDestroys = new List<RedNote>(note.Children);
                    for (int i = 0; i < waitDestroys.Count; i++)
                    {
                        if (!waitDestroys[i].IsDestroyed)
                        {
                            DestroyNote(waitDestroys[i].Key, true);
                        }
                    }
                }
            }
        }

        #endregion

        #region 状态传递部分
        
        public bool SetState(string key, bool active)
        {
            var note = GetNote(key);
            if (note != null && note.IsLeafNote())
            {
                bool chg = note.SetState(active);
                if (chg)
                {
                    MarkDirty(key, note.State);
                    
                    var ptr = note;
                    while (ptr != null && ptr.Parent != null)
                    {
                        chg = ptr.Parent.AfterChildStateUpdate(ptr.Key, ptr.State);
                        if (chg)
                        {
                            MarkDirty(ptr.Parent.Key, ptr.Parent.State);
                        }
                        
                        ptr = chg ? ptr.Parent : null;
                    }
                    return true;
                }
            }
            return false;
        }

        public IEnumerable<KeyValuePair<string, bool>> GetAllDirtyMarkRedNote()
        {
            return m_dirtyRedNotes;
        }

        public void ClearAllDirtyRedNoteMark()
        {
            m_dirtyRedNotes.Clear();
        }

        private void MarkDirty(string key, bool newState)
        {
            m_dirtyRedNotes[key] = newState;
        }
        #endregion
    }
}